home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / SOUND / AWECTRL.ZIP / AWECTRL.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-05  |  20.4 KB  |  763 lines

  1.     /****************************************/
  2.     /*   Low-level control of the EMU8000     */
  3.     /*        (c) Grinus/ToM,  1996         */
  4.     /*     Written for Borland C++ 3.1      */
  5.     /****************************************/
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. #include "awe.h"
  12.  
  13.  
  14. // ---------------  D a t a  --------------- //
  15.  
  16. WORD Port620 = 0;    // EMU base port address (0x620 resp. 0x640)
  17. WORD PortE22;           // secondary port address
  18.  
  19. WORD TbEffectCmd[4] = { AWE_28, AWE_2A, AWE_2C, AWE_2E };
  20.  
  21. WORD TbEffData1[128] = {
  22.     0x03FF, 0x0030, 0x07FF, 0x0130, 0x0BFF, 0x0230, 0x0FFF, 0x0330,
  23.     0x13FF, 0x0430, 0x17FF, 0x0530, 0x1BFF, 0x0630, 0x1FFF, 0x0730,
  24.     0x23FF, 0x0830, 0x27FF, 0x0930, 0x2BFF, 0x0A30, 0x2FFF, 0x0B30,
  25.     0x33FF, 0x0C30, 0x37FF, 0x0D30, 0x3BFF, 0x0E30, 0x3FFF, 0x0F30,
  26.     0x43FF, 0x0030, 0x47FF, 0x0130, 0x4BFF, 0x0230, 0x4FFF, 0x0330,
  27.     0x53FF, 0x0430, 0x57FF, 0x0530, 0x5BFF, 0x0630, 0x5FFF, 0x0730,
  28.     0x63FF, 0x0830, 0x67FF, 0x0930, 0x6BFF, 0x0A30, 0x6FFF, 0x0B30,
  29.     0x73FF, 0x0C30, 0x77FF, 0x0D30, 0x7BFF, 0x0E30, 0x7FFF, 0x0F30,
  30.     0x83FF, 0x0030, 0x87FF, 0x0130, 0x8BFF, 0x0230, 0x8FFF, 0x0330,
  31.     0x93FF, 0x0430, 0x97FF, 0x0530, 0x9BFF, 0x0630, 0x9FFF, 0x0730,
  32.     0xA3FF, 0x0830, 0xA7FF, 0x0930, 0xABFF, 0x0A30, 0xAFFF, 0x0B30,
  33.     0xB3FF, 0x0C30, 0xB7FF, 0x0D30, 0xBBFF, 0x0E30, 0xBFFF, 0x0F30,
  34.     0xC3FF, 0x0030, 0xC7FF, 0x0130, 0xCBFF, 0x0230, 0xCFFF, 0x0330,
  35.     0xD3FF, 0x0430, 0xD7FF, 0x0530, 0xDBFF, 0x0630, 0xDFFF, 0x0730,
  36.     0xE3FF, 0x0830, 0xE7FF, 0x0930, 0xEBFF, 0x0A30, 0xEFFF, 0x0B30,
  37.     0xF3FF, 0x0C30, 0xF7FF, 0x0D30, 0xFBFF, 0x0E30, 0xFFFF, 0x0F30
  38.     };
  39.  
  40. WORD TbEffData2[128] = {
  41.     0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
  42.     0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
  43.     0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
  44.     0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
  45.     0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
  46.     0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
  47.     0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
  48.     0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
  49.     0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
  50.     0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
  51.     0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
  52.     0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
  53.     0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
  54.     0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
  55.     0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
  56.     0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570
  57.     };
  58.  
  59. CHORUS_TYPE TbChorusTypes[8] = {
  60.     0xE600, 0x03F6, 0xBC2C, 0,     0x006D,    // Chorus 1
  61.     0xE608, 0x031A, 0xBC6E, 0,      0x017C,    // Chorus 2
  62.     0xE610, 0x031A, 0xBC84, 0,      0x0083,    // Chorus 3
  63.     0xE620, 0x0269, 0xBC6E, 0,      0x017C,    // Chorus 4
  64.     0xE680, 0x04D3, 0xBCA6, 0,     0x005B,    // Feedback Delay
  65.     0xE6E0, 0x044E, 0xBC37, 0,     0x0026,    // Flanger
  66.     0xE600, 0x0B06, 0xBC00, 0x6E000, 0x0083,    // Short Delay
  67.     0xE6C0, 0x0B06, 0xBC00, 0x6E000, 0x0083        // Short Delay FB
  68.     };
  69.  
  70. BYTE TbReverbReg[28] = {
  71.     0x03, 0x05, 0x7F, 0x07, 0x34, 0x36, 0x0F,
  72.     0x17, 0x1F, 0x27, 0x2F, 0x37, 0x3D, 0x3F,
  73.     0x41, 0x43, 0x09, 0x0B, 0x11, 0x13, 0x19,
  74.     0x1B, 0x21, 0x23, 0x29, 0x2B, 0x31, 0x33
  75.     };
  76.  
  77. WORD TbReverbData[8*28] = {
  78.     0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4, // Room 1
  79.     0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
  80.     0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
  81.     0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
  82.  
  83.     0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284, // Room 2
  84.     0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
  85.     0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
  86.     0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
  87.  
  88.     0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284, // Room 3
  89.     0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
  90.     0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
  91.     0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
  92.  
  93.     0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284, // Hall 1
  94.     0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
  95.     0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
  96.     0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
  97.  
  98.     0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254, // Hall 2
  99.     0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
  100.     0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
  101.     0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
  102.  
  103.     0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,    // Plate
  104.     0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
  105.     0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
  106.     0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
  107.  
  108.     0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,    // Delay
  109.     0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
  110.     0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
  111.     0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
  112.  
  113.     0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,    // Panning Delay
  114.     0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
  115.     0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
  116.     0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520
  117.     };
  118.  
  119. WORD TbAweBass[12*3] = {
  120.     0xD26A, 0xD36A, 0x0000,    // -12 dB
  121.     0xD25B, 0xD35B, 0x0000,    //  -8
  122.     0xD24C, 0xD34C, 0x0000,    //  -6
  123.     0xD23D, 0xD33D, 0x0000,    //  -4
  124.     0xD21F, 0xD31F, 0x0000,    //  -2
  125.     0xC208, 0xC308, 0x0001,    //   0 (HW default)
  126.     0xC219, 0xC319, 0x0001,    //  +2
  127.     0xC22A, 0xC32A, 0x0001,    //  +4
  128.     0xC24C, 0xC34C, 0x0001,    //  +6
  129.     0xC26E, 0xC36E, 0x0001,    //  +8
  130.     0xC248, 0xC348, 0x0002,    // +10
  131.     0xC26A, 0xC36A, 0x0002    // +12 dB
  132.     };
  133.  
  134. WORD TbAweTreble[12*9] = {
  135.     0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,    // -12 dB
  136.     0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,
  137.     0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,
  138.     0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,
  139.     0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,
  140.     0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002,
  141.     0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002,
  142.     0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002,
  143.     0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002,
  144.     0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002, // +8 (HW default)
  145.     0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002,
  146.     0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002    // +12 dB
  147.     };
  148.  
  149.  
  150. // ---------------  C o d e  --------------- //
  151.  
  152.  
  153. /*
  154.   Read the EMU base address from the BLASTER variable
  155.  */
  156. WORD GetBaseFromEnv()
  157. {
  158. char *p;
  159. WORD w;
  160.  
  161.  if (!(p = getenv("BLASTER"))
  162.      || !(p = strstr(p, " E"))
  163.      || sscanf(p+2, "%x", &w ) !=1 )
  164.     return 0;            // ERROR
  165.  return w;            // address
  166. }
  167.  
  168. // --------------- Low-level EMU8000 routines --------------- //
  169.  
  170. /*
  171.   Write the 16-bit EMU register
  172.  */
  173. void AweWrW(WORD reg, WORD data)
  174. {
  175.  asm {    mov ax, reg    // HighBYTE = register index,  LowBYTE = G-chan number
  176.  
  177.     mov cx,ax
  178.     mov cl,ch
  179.     and cx,0x6002
  180.     shr ch,3
  181.     add cx,Port620    // CX=port2
  182.  
  183.     and ax,0x1C1F
  184.     shl ah,3
  185.     or  al,ah
  186.     xor ah,ah    // AX=data1
  187.     mov dx,PortE22    // DX=port1
  188.  
  189.     cli        // start of critical section
  190.     out dx,ax
  191.     mov dx,cx       // DX=port2
  192.     mov ax, data    // AX=data2
  193.     out dx,ax
  194.     sti             // end of critical section
  195.     }
  196. }
  197.  
  198.  
  199. /*
  200.   Read the 16-bit EMU register
  201.  */
  202. WORD AweRdW(WORD reg)
  203. {
  204.  asm {    mov ax, reg
  205.     mov cx,ax
  206.     mov cl,ch
  207.     and cx,0x6002
  208.     shr ch,3
  209.     add cx,Port620
  210.     and ax,0x1C1F
  211.     shl ah,3
  212.     or  al,ah
  213.     xor ah,ah
  214.     mov dx,PortE22
  215.     cli
  216.     out dx,ax
  217.     mov dx,cx
  218.     in  ax,dx
  219.     sti
  220.     }
  221. #pragma warn -rvl
  222. }
  223. #pragma warn +rvl
  224.  
  225.  
  226. /*
  227.   Write the 32-bit EMU register
  228.  */
  229. void AweWrD(WORD reg, WORD hdata, WORD ldata )
  230. {
  231.  asm {    mov ax, reg
  232.     mov cx,ax
  233.     mov cl,ch
  234.     and cx,0x6002
  235.     shr ch,3
  236.     add cx,Port620
  237.     and ax,0x1C1F
  238.     shl ah,3
  239.     or  al,ah
  240.     xor ah,ah
  241.     mov dx,PortE22
  242.     cli
  243.     out dx,ax
  244.     mov dx,cx
  245.     mov ax,ldata
  246.     out dx,ax
  247.     inc dx
  248.     inc dx
  249.     mov ax,hdata
  250.     out dx,ax
  251.     sti
  252.     }
  253. }
  254.  
  255.  
  256. /*
  257.   Read the 32-bit EMU register
  258.  */
  259. DWORD AweRdD(WORD reg)
  260. {
  261.  asm {    mov ax, reg
  262.     mov cx,ax
  263.     mov cl,ch
  264.     and cx,0x6002
  265.     shr ch,3
  266.     add cx,Port620
  267.     and ax,0x1C1F
  268.     shl ah,3
  269.     or  al,ah
  270.     xor ah,ah
  271.     mov dx,PortE22
  272.     cli
  273.     out dx,ax
  274.     mov dx,cx
  275.     in  ax,dx
  276.     mov cx,ax
  277.     inc dx
  278.     inc dx
  279.     in  ax,dx
  280.     sti
  281.     mov  dx,ax
  282.     mov  ax,cx
  283.     }
  284. #pragma warn -rvl
  285. }
  286. #pragma warn +rvl
  287.  
  288.  
  289. /*
  290.   Detect the presence of the EMU8000
  291.  */
  292. int AweDetect1()
  293. {
  294. BYTE b;
  295. WORD w;
  296.  asm mov dx,Port620
  297.  asm add dx,0x802
  298.  asm mov PortE22,dx
  299.  asm in  al,dx
  300.  asm in  al,dx
  301.  asm not al
  302.  asm mov b,al
  303.  asm out dx,al        // invert the LowByte
  304.  asm in  al,dx
  305.  if ( _AL != b)
  306.     return 0;        // ERROR
  307.  asm in  ax,dx
  308.  asm mov w,ax
  309.  for (b = 128; 1; b--) {
  310.    asm in  ax,dx
  311.    if (_AX != w)
  312.       break;        // is it changing?
  313.    if (b==0)
  314.       return 0;        // if not, then ERROR
  315.    }
  316.  if ( (AweRdW(AWE_5C) & 0x8E) != 0x0C )
  317.     return 0;
  318.  b = ~AweRdW(0x241E) & 0x06;
  319.  w = ~AweRdW(0x241F) & 0x1F;
  320.  AweWrW(0x241E, w | b<<4);
  321.  if ( (AweRdW(0x241E) & 0x06) != b)
  322.     return 0;
  323.  AweWrW(0x241E, w | (~b<<4 & 0x60) );
  324.  
  325.  return 1;    // ok
  326. }
  327.  
  328.  
  329. /*
  330.   Determine the EMU8000 base port
  331.  */
  332. int AweDetect()
  333. {
  334.  if (Port620 == 0)        // the address is not forced ?
  335.     Port620 = GetBaseFromEnv();    // then let's try the BLASTER variable
  336.  
  337.  if (Port620 == 0) {        // still unknown?
  338.     Port620 = 0x620;        // Try 0x620
  339.     if (AweDetect1())
  340.        return 1;        // ok
  341.     Port620 += 0x20;        // Try 0x640
  342.     }
  343.  return AweDetect1();
  344. }
  345.  
  346.  
  347. /*
  348.   Wait for some EMU clocks (1/44100 sec)
  349.  */
  350. void AweWait(WORD delay)
  351. {
  352. WORD t0 = AweRdW(AWE_CLK);
  353.  while ( (WORD)( AweRdW(AWE_CLK) - t0 ) < delay )
  354.    ;
  355. }
  356.  
  357.  
  358. void InitEnvelopeEngine()
  359. {
  360.  for (WORD gchan = 0; gchan<32; gchan++) {
  361.     AweWrW( AWE_Env2Su_Dcy|gchan, 0x0080 );
  362.     AweWrW( AWE_Env1Ho_Att|gchan, 0 );
  363.     AweWrW( AWE_Env1Su_Dcy|gchan, 0 );
  364.     AweWrW( AWE_Pitch     |gchan, 0xD000 );
  365.     AweWrW( AWE_FC_Vol    |gchan, 0xFF00 );
  366.     AweWrW( AWE_Env1tP_tF |gchan, 0 );
  367.     AweWrW( AWE_Lfo1tP_tF |gchan, 0 );
  368.     AweWrW( AWE_Lfo1tV_F  |gchan, 0x0018 );
  369.     AweWrW( AWE_Lfo2tP_F  |gchan, 0x0018 );
  370.     AweWrW( AWE_58      |gchan, 0 );
  371.     AweWrW( AWE_Lfo2Dly   |gchan, 0 );
  372.     AweWrW( AWE_Lfo1Dly   |gchan, 0 );
  373.     AweWrW( AWE_Env2Ho_Att|gchan, 0 );
  374.     AweWrW( AWE_Env2Dly   |gchan, 0 );
  375.     AweWrW( AWE_Env1Dly   |gchan, 0 );
  376.     }
  377. }
  378.  
  379.  
  380. void InitSoundEngine()
  381. {
  382.  AweWrD(AWE_RdAdrD,   0x8000, 0x0000 );
  383.  AweWrD(AWE_RdAdrD+1, 0x8000, 0x0000 );
  384.  AweWrD(AWE_WrAdrD,   0x8000, 0x0000 );
  385.  AweWrD(AWE_WrAdrD+1, 0x8000, 0x0000 );
  386.  
  387.  for (WORD gchan = 0; gchan<32; gchan++) {
  388.     AweWrD( AWE_DP_Rev_Pan |gchan, 0, 0 );
  389.     AweWrD( AWE_DestV_FC   |gchan, 0, 0xFFFF );
  390.     AweWrD( AWE_CurrV_FC   |gchan, 0, 0xFFFF );
  391.     AweWrD( AWE_Pan_Loops  |gchan, 0, 0 );
  392.     AweWrD( AWE_Cho_Loope  |gchan, 0, 0 );
  393.     AweWrD( AWE_CurrPitch  |gchan, 0, 0 );
  394.     AweWrD( AWE_Flt_Start  |gchan, 0, 0 );
  395.     AweWrD( AWE_14       |gchan, 0, 0 );
  396.     AweWrD( AWE_10       |gchan, 0, 0 );
  397.     AweWrW( AWE_Env1Su_Dcy |gchan, 0x807F );
  398.     AweWrW( AWE_Env2Su_Dcy |gchan, 0x807F );
  399.     }
  400. }
  401.  
  402.  
  403. void InitEffects1(WORD near *data)
  404. {
  405. int i;
  406.  for (i=0; i<128; i++)
  407.     AweWrW( (i & 0x1F) | TbEffectCmd[i>>5 & 0x07], data[i] );
  408. }
  409.  
  410.  
  411. void InitEffects2(WORD near *data)
  412. {
  413. int i;
  414.  for (i=0; i<128; i++)
  415.     AweWrW( (i & 0x1F) | TbEffectCmd[i>>5 & 0x07], data[i] | i<<15 );
  416. }
  417.  
  418.  
  419. void InitEffectsEngine()
  420. {
  421. int i,j;
  422.  InitEffects1(TbEffData1);
  423.  AweWait(0x400);
  424.  for (i=0; i<0x14; i++)
  425.     AweWrD(0x2400|i, 0, 0 );
  426.  InitEffects2(TbEffData1);
  427.  InitEffects2(TbEffData2);
  428.  AweWrD(0x2409, 0, 0 );
  429.  AweWrD(0x240A, 0, 0x0083 );
  430.  AweWrD(0x240D, 0, 0x8000 );
  431.  AweWrD(0x240E, 0, 0 );
  432.  InitEffects1(TbEffData2);
  433. }
  434.  
  435.  
  436. /*
  437.   Prepare the last two channels for DRAM refresh and producing the reverb
  438.   and chorus effects for Yamaha OPL-3 synthesizer.
  439.  */
  440. void InitFMEffects(BYTE reverb, BYTE chorus)
  441. {
  442.  AweWrW(AWE_Env2Su_Dcy |30, 0x0080 );
  443.  AweWrD(AWE_Pan_Loops  |30, 0xFFFF, 0xFFE0 );
  444.  AweWrD(AWE_Cho_Loope  |30, 0x00FF | (WORD)chorus<<8, 0xFFE8 );
  445.  AweWrD(AWE_DP_Rev_Pan |30, 0, (WORD)reverb<<8 );
  446.  AweWrD(AWE_CurrPitch  |30, 0, 0 );
  447.  AweWrD(AWE_Flt_Start  |30, 0x00FF, 0xFFE3 );
  448.  
  449.  AweWrW(AWE_Env2Su_Dcy |31, 0x0080 );
  450.  AweWrD(AWE_Pan_Loops  |31, 0x00FF, 0xFFF0 );
  451.  AweWrD(AWE_Cho_Loope  |31, 0x00FF | (WORD)chorus<<8, 0xFFF8 );
  452.  AweWrD(AWE_DP_Rev_Pan |31, 0, 0x00FF | (WORD)reverb<<8 );
  453.  AweWrD(AWE_CurrPitch  |31, 0, 0x8000);
  454.  AweWrD(AWE_Flt_Start  |31, 0x00FF, 0xFFF3 );
  455.  
  456.  asm cli            // disable interrupts
  457.  asm mov  dx,PortE22
  458.  asm mov  ax,0x003E
  459.  asm out  dx,ax
  460.  
  461.  asm xchg bx,dx
  462.  asm mov  dx,Port620
  463.  asm xor  ax,ax
  464.  asm out  dx,ax
  465.  
  466.  asm xchg bx,dx            // 0xE22
  467.  loop1: asm in   ax,dx
  468.     asm test ah,0x10
  469.     asm jz   loop1
  470.  loop2:    asm in   ax,dx
  471.     asm test ah,0x10
  472.     asm jnz  loop2        // wait for an edge
  473.  
  474.  asm mov dx,bx
  475.  asm add dx,2            // 0x622
  476.  asm mov ax,0x4828
  477.  asm out dx,ax
  478.  
  479.  asm mov dx,PortE22
  480.  asm mov ax,0x003C
  481.  asm out dx,ax
  482.  
  483.  asm mov dx,bx
  484.  asm add dh,4            // 0xE20
  485.  asm xor ax,ax
  486.  asm out dx,ax
  487.  asm sti            // enable interrupts
  488.  
  489.  AweWrD(AWE_DestV_FC |30, 0x8000, 0xFFFF );
  490.  AweWrD(AWE_DestV_FC |31, 0x8000, 0xFFFF );
  491. }
  492.  
  493.  
  494. /*
  495.   Prepare some G-channels for the sample upload/download
  496.     rmode = 1    ->  odd G-channels for reading
  497.     rmode = 0   ->  all G-channels for writing
  498.  */
  499. void AweEnableRam(int rmode)
  500. {
  501. WORD gchan;
  502.  for (gchan=0; gchan<30; gchan++)
  503.     AweWrW( AWE_Env2Su_Dcy |gchan, 0x0080 );
  504.  
  505.  for (gchan=0; gchan<30; gchan++) {
  506.     AweWrD( AWE_DestV_FC   |gchan, 0, 0 );
  507.     AweWrD( AWE_CurrV_FC   |gchan, 0, 0 );
  508.     AweWrD( AWE_Pan_Loops  |gchan, 0, 0 );
  509.     AweWrD( AWE_Cho_Loope  |gchan, 0, 0 );
  510.     AweWrD( AWE_DP_Rev_Pan |gchan, 0x4000, 0x0000 );
  511.     AweWrD( AWE_CurrPitch  |gchan, 0x4000, 0x0000 );
  512.     // Read (4) / Write (6) mode
  513.     AweWrD( AWE_Flt_Start  |gchan, (gchan & rmode) ? 0x0400 : 0x0600, 0 );
  514.     }
  515. }
  516.  
  517.  
  518. void AweDisableRam()
  519. {
  520.  for (WORD gchan=0; gchan<30; gchan++)
  521.     AweWrD( AWE_Flt_Start  |gchan, 0, 0 ),
  522.     AweWrW( AWE_Env2Su_Dcy |gchan, 0x807F );
  523. }
  524.  
  525.  
  526. /*
  527.   Check the sample RAM size
  528.   This routine does not restore the changed sample data!
  529.  */
  530. WORD RamCheck()
  531. {
  532. WORD DRAMsize;        // [KB]
  533.  
  534.  AweEnableRam(1);    // we need both to read and write
  535.  
  536.  AweWrD(AWE_WrAdrD, TOPRAM>>16, TOPRAM&0xFFFF );    // 1-st addr in RAM
  537.  AweWrW(AWE_DataW,  0xE5A7 );
  538.  AweWrW(AWE_DataW,  0x1A58 );        // put a mark there
  539.  
  540.  for (DRAMsize=0; DRAMsize<28*1024; ) {
  541.     AweWait(2);
  542.     AweWrD(AWE_RdAdrD, TOPRAM>>16, TOPRAM&0xFFFF );    // back to 1-st addr
  543.     AweRdW(AWE_DataW);            // skip the 1-st word
  544.     if (AweRdW(AWE_DataW)!=0xE5A7)
  545.        break;
  546.     if (AweRdW(AWE_DataW)!=0x1A58)    // is the mark present?
  547.        break;
  548.     DRAMsize += 32;
  549.     AweWrD(AWE_WrAdrD, (TOPRAM>>16) + (DRAMsize>>7),
  550.                 (TOPRAM&0xFFFF) + (DRAMsize<<9) );
  551.     AweWrW(AWE_DataW, 0xFFFF);        // clear the mark
  552.     }
  553.  
  554.  AweDisableRam();
  555.  
  556.  return DRAMsize;
  557. }
  558.  
  559.  
  560. /*
  561.   Initialization of the EMU8000
  562.   (except the Equalizer and Effect settings)
  563.  */
  564. int AweInitHw()
  565. {
  566. WORD DRAMsize;
  567.  
  568.  if ( (AweRdW(AWE_5C) & 0x0E) != 0x0C)
  569.     return 0;            // ERROR
  570.  
  571.  AweWrW( 0x241D, 0x0059 );
  572.  AweWrW( 0x241E, 0x0020 );
  573.  AweWrW( 0x241F, 0 );
  574.  
  575.  InitEnvelopeEngine();
  576.  InitSoundEngine();
  577.  InitEffectsEngine();
  578.  
  579.  InitFMEffects( 102, 51 );    // Reverb 40%, Chorus 20%
  580.  
  581.  DRAMsize = RamCheck();
  582.  
  583.  AweWrW( 0x241F, 0x0006 );
  584.  if (~AweRdW(0x241E) & 0x40)
  585.     return 0;            // ERROR
  586.  
  587.  return DRAMsize;        // ok
  588. }
  589.  
  590.  
  591. /*
  592.   EMU clean-up routine
  593.   (called from 'exit' function)
  594.  */
  595. void AweTerminate()
  596. {
  597.  for (WORD gchan=30; gchan--; )
  598.     AweWrW( AWE_Env2Su_Dcy |gchan, 0x807F );    // All Sounds Off
  599.  
  600.  AweWait(2205);            // wait 50ms to avoid the reverb-click
  601.  
  602.  InitFMEffects( 102, 51 );    // Reverb & chorus for OPL3 synth
  603. }
  604.  
  605.  
  606. /*
  607.   Set the chorus type
  608.  */
  609. void AweChorusType(int type)
  610. {
  611. CHORUS_TYPE *t = TbChorusTypes + type;     // type = 0..7
  612.  
  613.  AweWrW(AWE_2C|0x09, t->FbkLevel );
  614.  AweWrW(AWE_2C|0x0C, t->Delay );
  615.  AweWrW(AWE_2E|0x03, t->LfoDepth );
  616.  AweWrD(AWE_24|0x09, HWORD(t->DelayR),  (WORD)t->DelayR );
  617.  AweWrD(AWE_24|0x0A, HWORD(t->LfoFreq), (WORD)t->LfoFreq );
  618.  AweWrD(AWE_24|0x0D, 0, 0x8000 );
  619.  AweWrD(AWE_24|0x0E, 0, 0 );
  620. }
  621.  
  622.  
  623. /*
  624.   Set the reverb type
  625.  */
  626. void AweReverbType(int type)
  627. {
  628. BYTE b;
  629.  for (int i=0; i<28; i++)
  630.     b = TbReverbReg[i],
  631.     AweWrW( TbEffectCmd[b>>5] | (b & 0x1F), TbReverbData[type*28+i] );
  632.  
  633. }
  634.  
  635.  
  636. /*
  637.   Send the values of EMU8000 digital equalizer
  638.  */
  639. void AweTrebleBass(int bass, int treble)
  640. {
  641.  // a range is 0..11  (-12dB .. +12dB)
  642. WORD w;
  643. WORD *pb = TbAweBass + bass*3;
  644. WORD *pt = TbAweTreble + treble*9;
  645.  
  646.  AweWrW(AWE_2E | 0x01, pb[0] );
  647.  AweWrW(AWE_2E | 0x11, pb[1] );
  648.  AweWrW(AWE_2C | 0x11, pt[0] );
  649.  AweWrW(AWE_2C | 0x13, pt[1] );
  650.  AweWrW(AWE_2C | 0x1B, pt[2] );
  651.  AweWrW(AWE_2E | 0x07, pt[3] );
  652.  AweWrW(AWE_2E | 0x0B, pt[4] );
  653.  AweWrW(AWE_2E | 0x0D, pt[5] );
  654.  AweWrW(AWE_2E | 0x17, pt[6] );
  655.  AweWrW(AWE_2E | 0x19, pt[7] );
  656.  w = pb[2] + pt[8];
  657.  AweWrW(AWE_2E | 0x15, w + 0x0263 );
  658.  AweWrW(AWE_2E | 0x1D, w - 0x7C9D );
  659. }
  660.  
  661.  
  662. /*
  663.   Send the block of 16-bit signed samples to the sample RAM,
  664.   provided that the sample RAM address is already set
  665.  */
  666. void AweWrBlock(WORD far *buf, WORD num_samps)
  667. {
  668.  asm mov cx,num_samps
  669.  asm jcxz retdlr
  670.  asm mov dx,PortE22
  671.  asm mov ax,0x003A
  672.  asm out dx,ax
  673.  asm mov dx,Port620
  674.  asm add dh,4
  675.  asm push ds
  676.  asm lds si,buf
  677.  asm cld
  678.    loopdlr16:
  679.    asm lodsw
  680.    asm out dx,ax
  681.    asm loop loopdlr16
  682.  asm pop ds
  683.  retdlr:
  684. }
  685.  
  686.  
  687. /*
  688.   Send the NoteOff cmd
  689.   (in fact, it just starts the release phase)
  690.  */
  691. void NoteOff(int gChan)
  692. {
  693.  // Start the fastest decay to a zero level
  694.  AweWrW( AWE_Env2Su_Dcy |gChan, 0x807F );
  695.  
  696.  /* ENV1 was not used
  697.  AweWrW( AWE_Env1Su_Dcy |gChan, 0x807F );
  698.   */
  699. }
  700.  
  701.  
  702. /*
  703.   The fastest possible destroing of the note
  704.   It can cause a click!
  705.  */
  706. void CutNote(int gChan)
  707. {
  708.  AweWrW(AWE_Env2Su_Dcy|gChan, 0x0080);        // disable the volume envelope
  709.  AweWrD(AWE_DestV_FC  |gChan, 0, 0xFFFF);    // dest. volume = 0
  710. }
  711.  
  712.  
  713. /*
  714.   Start the new note
  715.   It expects that all necessary values are already prepared.
  716.  */
  717. void AweNoteOn( int   gChan,         // 0..29
  718.         BYTE  Volume,         // log. 255..0  (min..max)
  719.         BYTE  Pan,               // 00..FF (left..right)
  720.         BYTE  Reverb,         // lin. 00..FF
  721.         BYTE  Chorus,            // lin. 00..FF
  722.         WORD  AwePitch,         // log. 0000..FFFF
  723.         WORD  AweLinPitch,     // lin. 0000..FFFF
  724.         DWORD Start,         // 000000..FFFFFF
  725.         DWORD LoopS, DWORD LoopE // 000000..FFFFFF
  726.           )
  727. {
  728.  // Send the G-channel params
  729.  AweWrD( AWE_DestV_FC   |gChan, 0, 0xFFFF );    // CurrVol=0, CurrFC=0xFFFF
  730.  AweWrW( AWE_Env2Ho_Att |gChan, 0x7F7E);    // ENV2 Hold = 0, Attack = 6ms
  731.  AweWrW( AWE_Lfo1Dly    |gChan, 0x8000 );    // LFO1 Delay = 0
  732.  AweWrW( AWE_Env1Ho_Att |gChan, 0x7F7F );    // ENV1 Hold & Attack = 0
  733.  AweWrW( AWE_Env1Su_Dcy |gChan, 0x807F );    // ENV1 Sustain & Decay = 0
  734.  AweWrW( AWE_Lfo2Dly    |gChan, 0x8000 );    // LFO2 Delay = 0
  735.  AweWrW( AWE_Pitch      |gChan, AwePitch );    // Pitch
  736.  AweWrW( AWE_FC_Vol     |gChan, 0xFF00|Volume); // FiltCutoff & Volume
  737.  AweWrW( AWE_Env1tP_tF  |gChan, 0x0000 );    // ENV1 ToPitch & ToFilter
  738.  AweWrW( AWE_Lfo1tP_tF  |gChan, 0x0000 );    // LFO1 ToPitch & ToFilter
  739.  AweWrW( AWE_Lfo1tV_F   |gChan, 0x0000 );    // LFO1 ToVolume & Freq
  740.  AweWrW( AWE_Lfo2tP_F   |gChan, 0x0000 );    // LFO2 ToPitch & Freq
  741.  AweWrW( AWE_Env1Dly    |gChan, 0x8000 );    // ENV1 Delay = 0
  742.  AweWrW( AWE_Env2Dly    |gChan, 0x8000 );    // ENV2 Delay = 0
  743.  AweWrD( AWE_CurrV_FC     |gChan, 0, 0xFFFF );    // CurrVol=0, CurrFC=max
  744.  AweWrD( AWE_DP_Rev_Pan    |gChan, AweLinPitch,    // DestPitch
  745.                   (WORD)Reverb<<8   // ReverbLevel
  746.                   |  Pan );        // RightPan
  747.  AweWrD( AWE_Pan_Loops    |gChan,
  748.            (WORD)(~Pan) <<8            // LeftPan
  749.            | HWORD(LoopS), (WORD)LoopS );    // LoopS
  750.  AweWrD( AWE_Cho_Loope  |gChan, (WORD)Chorus<<8 // Chorus
  751.            | HWORD(LoopE), (WORD)LoopE );    // LoopE
  752.  AweWrD( AWE_Flt_Start  |gChan, 0          // FilterQ=0, RamMode=Normal
  753.            | HWORD(Start), (WORD)Start );    // Start
  754.  AweWrD( AWE_14     |gChan, 0, 0 );        // ???
  755.  AweWrD( AWE_10     |gChan, 0, 0 );         // ???
  756.  AweWrD( AWE_DestV_FC    |gChan, 0, 0xFF00 );    // DestVol=0, DestFC=0xFF00
  757.  AweWrD( AWE_CurrV_FC    |gChan, 0, 0xFF00 );    // CurrVol=0, CurrFC=0xFF00
  758.  AweWrD( AWE_CurrPitch    |gChan, AweLinPitch, 0);// CurrPitch
  759.  
  760.  // Now start the note and envelopes
  761.  AweWrW( AWE_Env2Su_Dcy |gChan, 0x7F01 );    // ENV2 Sustain=max & Decay=min
  762. }
  763.